#!/usr/bin/python

import httplib
import httplib2
import os
import random
import sys
import time
import ca_certs_locater



from apiclient.discovery import build
from apiclient.errors import HttpError
from apiclient.http import MediaFileUpload
from oauth2client.file import Storage
from oauth2client.client import flow_from_clientsecrets
from oauth2client.tools import run
from optparse import OptionParser
import logging

import argparse
from oauth2client import tools
from oauth2client.tools import argparser
from oauth2client.tools import run_flow

def resource_path(relative):
    return os.path.join(
        os.environ.get(
            "_MEIPASS2",
            os.path.abspath(".")
        ),
        relative
    )

# Explicitly tell the underlying HTTP transport library not to retry, since
# we are handling retry logic ourselves.
httplib2.RETRIES = 1

# Maximum number of times to retry before giving up.
MAX_RETRIES = 10

# Always retry when these exceptions are raised.
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected,
  httplib.IncompleteRead, httplib.ImproperConnectionState,
  httplib.CannotSendRequest, httplib.CannotSendHeader,
  httplib.ResponseNotReady, httplib.BadStatusLine)

# Always retry when an apiclient.errors.HttpError with one of these status
# codes is raised.
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]


# A limited OAuth 2 access scope that allows for uploading files, but not other
# types of account access.
YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"

# Helpful message to display if the CLIENT_SECRETS_FILE is missing.
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0

To make this sample run you will need to populate the client_secrets.json file
found at:

   %s

with information from the APIs Console
https://code.google.com/apis/console#access

For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
"""





class UploadVideo:
    def __init__(self,file=None,title="Default_Title",description="Test Description",
                 keywords= "",
                 privacyStatus="public",
                 category="25",
                 flags=None,
                 edir=""):
        self._file = file
        self._title = title
        self._description = description
        self._keywords = keywords
        self._privacyStatus = privacyStatus
        self._category = category
        self.edir = edir
        if flags == None:
                parser = argparse.ArgumentParser(description=__doc__,
                            formatter_class=argparse.RawDescriptionHelpFormatter,
                            parents=[tools.argparser])
                self._flags = parser.parse_args('')
        else:
            self._flags = flags

    
    def get_authenticated_service(self):
        logging.debug("Flow from Client Secret")
        # CLIENT_SECRETS_FILE, name of a file containing the OAuth 2.0 information for
        # this application, including client_id and client_secret. You can acquire an
        # ID/secret pair from the API Access tab on the Google APIs Console
        #   http://code.google.com/apis/console#access
        # For more information about using OAuth2 to access Google APIs, please visit:
        #   https://developers.google.com/accounts/docs/OAuth2
        # For more information about the client_secrets.json file format, please visit:
        #   https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
        # Please ensure that you have enabled the YouTube Data API for your project.
        CLIENT_SECRETS_FILE = "client_secrets.json"
        CLIENT_SECRETS_FILE = os.path.join(self.edir,CLIENT_SECRETS_FILE)

               
        try:
            f = open(CLIENT_SECRETS_FILE,"r")
            f.close()
        except:
            logging.error("Unable to open clien secret file")
            raise
        CLIENT_SECRETS_FILE = resource_path(CLIENT_SECRETS_FILE)
        flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_UPLOAD_SCOPE,
        message=MISSING_CLIENT_SECRETS_MESSAGE)

    
        storage = Storage(os.path.join(self.edir,"%s-oauth2.json" % sys.argv[0]))
        credentials = storage.get()
        
        if credentials is None or credentials.invalid:
            logging.debug("First time credential")
            credentials = run_flow(flow, storage,self._flags)

        logging.debug("Building api paths")
        return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
        http=credentials.authorize(httplib2.Http()))
        
    def initialize_upload(self):
        logging.debug("Start getting Authenticated Service")
        youtube = self.get_authenticated_service()
        tags = None
        if self._keywords:
            tags = self._keywords.split(",")
        
        
        insert_request = youtube.videos().insert(part="snippet,status",body=dict(snippet=dict(title=self._title,description=self._description,tags=tags,categoryId=self._category),status=dict(privacyStatus=self._privacyStatus)),
        # chunksize=-1 means that the entire file will be uploaded in a single
        # HTTP request. (If the upload fails, it will still be retried where it
        # left off.) This is usually a best practice, but if you're using Python
        # older than 2.6 or if you're running on App Engine, you should set the
        # chunksize to something like 1024 * 1024 (1 megabyte).
        
        media_body=MediaFileUpload(self._file, chunksize=-1, resumable=True)
        )
        self.resumable_upload(insert_request)


    def resumable_upload(self,insert_request):
        response = None
        error = None
        retry = 0
        while response is None:
            try:
                status, response = insert_request.next_chunk()
                if 'id' in response:
                     logging.debug("'%s' (video id: %s) was successfully uploaded." % (self._title, response['id']))
                     print ("'%s' (video id: %s) was successfully uploaded." % (self._title, response['id']))

                else:
                    exit("The upload failed with an unexpected response: %s" % response)
            except HttpError, e:
                if e.resp.status in RETRIABLE_STATUS_CODES:
                    error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status,e.content)
                else:
                    raise
            except RETRIABLE_EXCEPTIONS, e:
                error = "A retriable error occurred: %s" % e
            if error is not None:
                logging.error(error)
                retry += 1
                if retry > MAX_RETRIES:
                    exit("No longer attempting to retry.")

                max_sleep = 2 ** retry
                sleep_seconds = random.random() * max_sleep
                logging.info("Sleeping %f seconds and then retrying..." % sleep_seconds)
                time.sleep(sleep_seconds)

#  http=httplib2.Http()
#  http.disable_ssl_certificate_validation = True
#  credentials = flow.step2_exchange(code, http)
#  return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,http)

if __name__ == '__main__':

    parser = argparse.ArgumentParser(description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    parents=[tools.argparser])
    
    parser.add_argument('--file',dest="file",default=None,help="Video file to upload")
    parser.add_argument("--title", dest="title", help="Video title",default="Default title")
    parser.add_argument("--description", dest="description",help="Video description",default="Test Description")
    parser.add_argument("--category", dest="category",help="Numeric video category. " +
                        "See https://developers.google.com/youtube/v3/docs/videoCategories/list",
                         default="22")
    parser.add_argument("--keywords", dest="keywords",help="Video keywords, comma separated", default="")
    parser.add_argument("--privacyStatus", dest="privacyStatus",
                        help="Video privacy status: public, private or unlisted",default="public")
                        
    flags = parser.parse_args()

    if flags.file is None or not os.path.exists(flags.file):
      exit("Please specify a valid file using the --file= parameter.")
    else:
        uvideo = UploadVideo(file=flags.file,
                             title=flags.title,
                             description=flags.description,
                             keywords=flags.keywords,
                             privacyStatus=flags.privacyStatus,
                             edir=".//") 
        uvideo.initialize_upload()
